package com.insight.service;

import com.insight.entity.OperationLog;
import com.insight.repository.OperationLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * T120: OperationLogService审计日志记录服务
 * 提供统一的操作日志记录功能
 *
 * @author Insight Team
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OperationLogService {

    private final OperationLogRepository operationLogRepository;

    /**
     * 记录操作日志(同步)
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public OperationLog log(OperationLog operationLog) {
        try {
            return operationLogRepository.save(operationLog);
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
            // 日志保存失败不应该影响主业务流程
            return operationLog;
        }
    }

    /**
     * 异步记录操作日志
     */
    @Async
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAsync(OperationLog operationLog) {
        try {
            operationLogRepository.save(operationLog);
        } catch (Exception e) {
            log.error("异步保存操作日志失败", e);
        }
    }

    /**
     * 记录成功的操作
     */
    public void logSuccess(String operationType, String module, String description,
                           String url, Long executionTime) {
        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .requestUrl(url)
                .executionTime(executionTime)
                .success(true)
                .build();

        logAsync(log);
    }

    /**
     * 记录失败的操作
     */
    public void logFailure(String operationType, String module, String description,
                           String url, String errorMessage, Long executionTime) {
        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .requestUrl(url)
                .errorMessage(errorMessage)
                .executionTime(executionTime)
                .success(false)
                .build();

        logAsync(log);
    }

    /**
     * 记录异常操作
     */
    public void logException(String operationType, String module, String description,
                             String url, Exception exception, Long executionTime) {
        String errorMessage = exception.getMessage();
        String stackTrace = getStackTrace(exception);

        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .requestUrl(url)
                .errorMessage(errorMessage)
                .errorStackTrace(stackTrace)
                .executionTime(executionTime)
                .success(false)
                .build();

        logAsync(log);
    }

    /**
     * 记录资源相关操作
     */
    public void logResourceOperation(String operationType, String module, String description,
                                      String resourceType, Long resourceId,
                                      String url, Long executionTime) {
        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .resourceType(resourceType)
                .resourceId(resourceId)
                .requestUrl(url)
                .executionTime(executionTime)
                .success(true)
                .build();

        logAsync(log);
    }

    /**
     * 记录带请求参数的操作
     */
    public void logWithParams(String operationType, String module, String description,
                              String method, String url, String params, Long executionTime) {
        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .requestMethod(method)
                .requestUrl(url)
                .requestParams(params)
                .executionTime(executionTime)
                .success(true)
                .build();

        logAsync(log);
    }

    /**
     * 记录带客户端信息的操作
     */
    public void logWithClient(String operationType, String module, String description,
                              String url, String ip, String userAgent, Long executionTime) {
        OperationLog log = OperationLog.builder()
                .operationType(operationType)
                .operationModule(module)
                .operationDescription(description)
                .requestUrl(url)
                .operatorIp(ip)
                .operatorUserAgent(userAgent)
                .executionTime(executionTime)
                .success(true)
                .build();

        logAsync(log);
    }

    /**
     * 将异常堆栈转换为字符串
     */
    private String getStackTrace(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }
}
